﻿#pragma once
#include "XyNet/Common/Id.h"

namespace XyNet
{
	class RpcBroadcastChannel;
	class RpcChannel;
	class RpcEndpoint;
	class RpcServiceManager;
	class RpcSocketChannel;

	/// rpc错误
	class XYNET_API RpcError// : noncopyable	// 不能用noncopyable
	{
	public:
		RpcError(int code, const string& name, const string& brief);

		/// 获取错误码
		inline int getCode() const { return _code; }
		/// 获取错误名
		inline const string& getName() const { return _name; }
		/// 获取错误概要
		inline const string& getBrief() const { return _brief; }

		/// 获取详细错误信息
		inline const string& getDetail() const { return _detail; }
		/// 设置详细错误信息
		inline void setDetail(const string& detail) { _detail = detail; }

		/// 获取错误信息
		string getInfo() const;

	private:
		/// 错误码，0表示无错误
		int _code;
		/// 错误名
		string _name;
		/// 错误概要
		string _brief;
		/// 错误详细信息
		string _detail;
	};

	//////////////////////////////////////////////////////////////////////////

	/// rpc消息控制器，保存用户ID，通道，错误等信息
	class XYNET_API RpcController : noncopyable
	{
	public:
		RpcController(RpcSocketChannel* socketChannel);
		virtual ~RpcController();

		/// 获取套接字通道（用于服务端主动发消息，增删权限相关服务等）
		shared_ptr<RpcChannel> getChannel();
		/// 创建广播通道（用于服务端广播）
		shared_ptr<RpcBroadcastChannel> createBroadcastChannel();

		/// 获取套接字通道id
		const Id& getSocketChannelId() const;
		/// 获取套接字通道服务管理器
		shared_ptr<RpcServiceManager> getSocketChannelServiceManager();

		/// 获取用户数据
		template <typename Type>
		Type getUserData() const
		{
			return _socketChannel->getUserData<Type>();
		}
		/// 设置用户数据
		template <typename Type>
		void setUserData(const Type& userData)
		{
			_socketChannel->setUserData(userData);
		}
		/// 清理用户数据和服务管理器服务（用于用户登出，清除服务是防止非法使用服务）
		void clearUserDataAndService();

		/// 是否失败
		bool isFailed() const;
		/// 设置失败文本（调用此函数会标记异常未被处理，如果是客户端设置失败，回调结束后会抛出失败异常）
		void setFailed(int code, const string& detail = "");
		/// 获取错误（调用此函数会标记异常被处理）
		shared_ptr<const RpcError> getError() const;

		/// 创建错误。先找自身定义的错误，后找基类基本错误。如果找不到，返回未知错误
		virtual shared_ptr<RpcError> createError(int code) const;

	private:
		/// 所属套接字通道
		RpcSocketChannel* _socketChannel;

		/// 控制器所属消息错误
		shared_ptr<RpcError> _error;
	};
}